package net.sansi.v3correctserver.entity.screen;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import net.sansi.v3correctserver.entity.HashEquals;
import net.sansi.v3correctserver.entity.IntLine;
import net.sansi.v3correctserver.entity.IntPoint;

import java.util.Objects;

/**
 * Created by Fang
 * create time : 2024/11/4
 * IDE : IntelliJ IDEA
 * <p>
 * 矩形
 */
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class Rect extends HashEquals {

    public Rect(int x, int y, int width, int height) {
        this.width = width;
        this.height = height;
        this.start = new IntPoint(x, y);
    }

    @ApiModelProperty("宽度")
    private Integer width;

    public int getWidth() {
        return width;
    }

    @ApiModelProperty("高度")
    private Integer height;

    public int getHeight() {
        return height;
    }

    @ApiModelProperty("起始点")
    private IntPoint start = new IntPoint(0, 0);

    @ApiModelProperty("围栏[上，右，下，左]")
    @JsonIgnore
    public int[] getFence() {
        return new int[]{getTop(), getRight(), getBottom(), getLeft()};
    }

    @ApiModelProperty("上边界")
    @JsonIgnore
    public int getTop() {
        return start.getY();
    }

    @ApiModelProperty("右边界")
    @JsonIgnore
    public int getRight() {
        return start.getX() + width - 1;
    }

    @ApiModelProperty("下边界")
    @JsonIgnore
    public int getBottom() {
        return start.getY() + height - 1;
    }

    @ApiModelProperty("左边界")
    @JsonIgnore
    public int getLeft() {
        return start.getX();
    }

    @ApiModelProperty("面积")
    @JsonIgnore
    public int getArea() {
        return width * height;
    }

    /**
     * 扩展当前区域
     *
     * @param extendWidth  扩展宽度
     * @param extendHeight 扩展高度
     * @param correctRange 矫正范围
     * @return Rect
     */
    public Rect toExtend(int extendWidth, int extendHeight, Rect correctRange) {
        IntPoint leftTop = new IntPoint(
                Math.max(getLeft() - extendWidth, correctRange.getLeft()),
                Math.max(getTop() - extendHeight, correctRange.getTop())
        );

        IntPoint rightBottom = new IntPoint(
                Math.min(getRight() + extendWidth, correctRange.getRight()),
                Math.min(getBottom() + extendHeight, correctRange.getBottom())
        );
        return of(leftTop, rightBottom);
    }

    /**
     * 通过左上角和 右下角 获取矩形
     *
     * @param leftTop     左上角
     * @param rightBottom 右下角
     * @return Rect
     */
    public static Rect of(IntPoint leftTop, IntPoint rightBottom) {
        return new Rect(
                rightBottom.getX() - leftTop.getX() + 1,
                rightBottom.getY() - leftTop.getY() + 1,
                leftTop
        );
    }

    /**
     * 通过左上角坐标和宽高获取矩形
     *
     * @param x      左上角x
     * @param y      左上角y
     * @param width  宽
     * @param height 高
     * @return Rect
     */
    public static Rect of(int x, int y, int width, int height) {
        return new Rect(width, height, new IntPoint(x, y));
    }

    /**
     * 根据方向获取边线
     *
     * @param dir 方向 0 - 上，1 - 右，2 - 下，3 - 左
     * @return 边线
     */
    @JsonIgnore
    public IntLine getLine(int dir) {
        return switch (dir) {
            case 0 -> new IntLine(getPoint(0), getPoint(1));
            case 1 -> new IntLine(getPoint(1), getPoint(2));
            case 2 -> new IntLine(getPoint(3), getPoint(2));
            case 3 -> new IntLine(getPoint(0), getPoint(3));
            default -> null;
        };
    }

    /**
     * 获取四个边线
     *
     * @return 四条边线
     */
    @JsonIgnore
    public IntLine[] getLines() {
        return new IntLine[]{getLine(0), getLine(1), getLine(2), getLine(3)};
    }

    /**
     * 按照方向获取四个角上的坐标点
     *
     * @param dir 方向 0 - 左上 1 - 右上 2 - 右下 3 - 左下
     * @return 点
     */
    @JsonIgnore
    public IntPoint getPoint(int dir) {
        return switch (dir) {
            case 0 -> new IntPoint(start.getX(), start.getY());
            case 1 -> new IntPoint(start.getX() + width - 1, start.getY());
            case 2 -> new IntPoint(start.getX() + width - 1, start.getY() + height - 1);
            case 3 -> new IntPoint(start.getX(), start.getY() + height - 1);
            default -> null;
        };
    }

    /**
     * 获取右下角坐标
     *
     * @return 右下角坐标
     */
    @JsonIgnore
    public IntPoint getRBPoint() {
        return getPoint(2);
    }

    /**
     * 获取四个角上的坐标点
     *
     * @return 四个点（左上，右上，右下，左下）
     */
    @JsonIgnore
    public IntPoint[] getPoints() {
        return new IntPoint[]{getPoint(0), getPoint(1), getPoint(2), getPoint(3)};
    }

    /**
     * 回调接口
     */
    public interface ForeachCallback {
        void callback(int x, int y);
    }

    /**
     * 遍历该区域每个坐标
     *
     * @param iterator 回调
     */
    public void foreach(ForeachCallback iterator) {
        int l = getLeft(), r = getRight(), t = getTop(), b = getBottom();
        for (int x = l; x <= r; x++) {
            for (int y = t; y <= b; y++) {
                iterator.callback(x, y);
            }
        }
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

    @Override
    public int hashCode() {
        return Objects.hash(getWidth(), getHeight(), getStart().hashCode());
    }
}
